/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.util; import java.awt.event.KeyEvent; import java.util.*; import java.util.List; import java.lang.reflect.*; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import javax.swing.KeyStroke; import java.awt.*; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.Vector; import org.openide.TopManager; /** Otherwise uncategorized useful static methods. * * @author Jan Palka, Ian Formanek, Jaroslav Tulach */ final public class Utilities { private Utilities () {} /** Operating system is Windows NT. */ public static final int OS_WINNT = 1; /** Operating system is Windows 95. */ public static final int OS_WIN95 = 2; /** Operating system is Windows 98. */ public static final int OS_WIN98 = 4; /** Operating system is Solaris. */ public static final int OS_SOLARIS = 8; /** Operating system is Linux. */ public static final int OS_LINUX = 16; /** Operating system is HP-UX. */ public static final int OS_HP = 32; /** Operating system is IBM AIX. */ public static final int OS_AIX = 64; /** Operating system is SGI IRIX. */ public static final int OS_IRIX = 128; /** Operating system is Sun OS. */ public static final int OS_SUNOS = 256; /** Operating system is DEC (Digital Unix). */ public static final int OS_DEC = 512; /** Operating system is OS/2. */ public static final int OS_OS2 = 1024; /** Operating system is Mac. */ public static final int OS_MAC = 2048; /** Operating system is Windows 2000. */ public static final int OS_WIN2000 = 4096; /** Operating system is unknown. */ public static final int OS_OTHER = 65536; /** A mask for Windows platforms. */ public static final int OS_WINDOWS_MASK = OS_WINNT | OS_WIN95 | OS_WIN98 | OS_WIN2000; /** A mask for Unix platforms. */ public static final int OS_UNIX_MASK = OS_SOLARIS | OS_LINUX | OS_HP | OS_AIX | OS_IRIX | OS_SUNOS | OS_DEC; /** hashtable that maps allowed key names to their values (String, Integer) * @associates Integer*/ private static Map names; /** hashtable for mapping of values to their names * @associates String*/ private static Map values; static { initialize (); } /** Get the operating system on which the IDE is running. * @return one of the <code>OS_*</code> constants (such as {@link #OS_WINNT}) */ public static final int getOperatingSystem () { if (operatingSystem == -1) { String osName = System.getProperty ("os.name"); if ("Windows NT".equals (osName)) // NOI18N operatingSystem = OS_WINNT; else if ("Windows 95".equals (osName)) // NOI18N operatingSystem = OS_WIN95; else if ("Windows 98".equals (osName)) // NOI18N operatingSystem = OS_WIN98; else if ("Windows 2000".equals (osName)) // NOI18N operatingSystem = OS_WIN2000; else if ("Solaris".equals (osName)) // NOI18N operatingSystem = OS_SOLARIS; else if (osName.startsWith ("SunOS")) // NOI18N operatingSystem = OS_SOLARIS; else if ("Linux".equals (osName)) // NOI18N operatingSystem = OS_LINUX; else if ("HP-UX".equals (osName)) // NOI18N operatingSystem = OS_HP; else if ("AIX".equals (osName)) // NOI18N operatingSystem = OS_AIX; else if ("Irix".equals (osName)) // NOI18N operatingSystem = OS_IRIX; else if ("SunOS".equals (osName)) // NOI18N operatingSystem = OS_SUNOS; else if ("Digital UNIX".equals (osName)) // NOI18N operatingSystem = OS_DEC; else if ("OS/2".equals (osName)) // NOI18N operatingSystem = OS_OS2; else if ("Mac OS".equals (osName)) // NOI18N operatingSystem = OS_MAC; else operatingSystem = OS_OTHER; } return operatingSystem; } /** Test whether the IDE is running on some variant of Windows. * @return <code>true</code> if Windows, <code>false</code> if some other manner of operating system */ public static final boolean isWindows () { return (getOperatingSystem () & OS_WINDOWS_MASK) != 0; } /** Test whether the IDE is running on some variant of Unix. * Linux is included as well as the commercial vendors. * @return <code>true</code> some sort of Unix, <code>false</code> if some other manner of operating system */ public static final boolean isUnix () { return (getOperatingSystem () & OS_UNIX_MASK) != 0; } /** The operating system on which NetBeans runs*/ private static int operatingSystem = -1; /** Hashtable contains keywords. It is forbidden to use this keywords as a java identifier * @associates String*/ static java.util.Hashtable keywords; static { keywords = new java.util.Hashtable(); keywords.put("abstract","abstract"); keywords.put("default","default"); // NOI18N keywords.put("if","if"); keywords.put("private","private"); // NOI18N keywords.put("throw","throw"); keywords.put("boolean","boolean"); // NOI18N keywords.put("do","do"); keywords.put("implements","implements"); // NOI18N keywords.put("protected","protected"); keywords.put("throws","throws"); // NOI18N keywords.put("break","break"); keywords.put("double","double"); // NOI18N keywords.put("import","import"); keywords.put("public","public"); // NOI18N keywords.put("transient","transient");keywords.put("byte","byte"); // NOI18N keywords.put("else","else");keywords.put("instanceof","instanceof"); // NOI18N keywords.put("return","return");keywords.put("try","try"); // NOI18N keywords.put("case","case");keywords.put("extends","extends"); // NOI18N keywords.put("int","int");keywords.put("short","short"); // NOI18N keywords.put("void","void");keywords.put("catch","catch"); // NOI18N keywords.put("final","final");keywords.put("interface","interface"); // NOI18N keywords.put("static","static");keywords.put("volatile","volatile"); // NOI18N keywords.put("char","char");keywords.put("finally","finally"); // NOI18N keywords.put("long","long");keywords.put("class","class"); // NOI18N keywords.put("while","while");keywords.put("super","super"); // NOI18N keywords.put("float","float");keywords.put("native","native"); // NOI18N keywords.put("switch","switch");keywords.put("const","const"); // NOI18N keywords.put("for","for");keywords.put("new","new"); // NOI18N keywords.put("synchronized","synchronized");keywords.put("continue","continue"); // NOI18N keywords.put("continue","continue");keywords.put("goto","goto"); // NOI18N keywords.put("package","package");keywords.put("this","this"); // NOI18N keywords.put("null","null");keywords.put("true","true"); // NOI18N keywords.put("false","false"); // NOI18N } /** Test whether a given string is a valid Java identifier. * @param id string which should be checked * @return <code>true</code> if a valid identifier */ public static final boolean isJavaIdentifier(String id) { if (id == null) return false; if (id.equals("")) return false; // NOI18N if (!(java.lang.Character.isJavaIdentifierStart(id.charAt(0))) ) return false; for (int i = 1; i < id.length(); i++) { if (!(java.lang.Character.isJavaIdentifierPart(id.charAt(i))) ) return false; } // test if id is a keyword if (keywords.containsKey(id)) return false; return true; } /** Central method for obtaining <code>BeanInfo</code> for potential JavaBean classes. * This implementation provides additional functionality for Swing bean infos. * @param clazz class of the bean to provide the <code>BeanInfo</code> for * @return the bean info * @throws java.beans.IntrospectionException for the usual reasons * @see java.beans.Introspector#getBeanInfo(Class) */ public static java.beans.BeanInfo getBeanInfo(Class clazz) throws java.beans.IntrospectionException { java.beans.BeanInfo bi; if (clazz.getName().startsWith("javax.swing")) // NOI18N bi = SwingEditors.scanAndSetBeanInfo(java.beans.Introspector.getBeanInfo(clazz)); else bi = java.beans.Introspector.getBeanInfo(clazz); if (java.awt.Component.class.isAssignableFrom (clazz)) { java.beans.PropertyDescriptor[] pds = bi.getPropertyDescriptors (); for (int i = 0; i < pds.length; i++) { if (pds[i].getName ().equals ("cursor")) { // NOI18N try { Method getter = Component.class.getDeclaredMethod ("getCursor", new Class[0]); // NOI18N Method setter = Component.class.getDeclaredMethod ("setCursor", new Class[] { Cursor.class }); // NOI18N pds[i] = new java.beans.PropertyDescriptor ("cursor", getter, setter); // NOI18N } catch (NoSuchMethodException e) { e.printStackTrace(); } break; } } } return bi; } /** Central method for obtaining <code>BeanInfo</code> for potential JavaBean classes, with a stop class. * This implementation provides additional functionality for Swing bean infos. * @param clazz class of the bean to provide the <code>BeanInfo</code> for * @param stopClass the stop class * @return the bean info * @throws java.beans.IntrospectionException for the usual reasons * @see java.beans.Introspector#getBeanInfo(Class, Class) */ public static java.beans.BeanInfo getBeanInfo (Class clazz, Class stopClass) throws java.beans.IntrospectionException { if (clazz.getName().startsWith("javax.swing")) // NOI18N return SwingEditors.scanAndSetBeanInfo(java.beans.Introspector.getBeanInfo (clazz, stopClass)); else return java.beans.Introspector.getBeanInfo(clazz, stopClass); } /** Wrap multi-line strings (and get the individual lines). * @param original the original string to wrap * @param width the maximum width of lines * @param wrapWords if <code>true</code>, the lines are wrapped on word boundaries (if possible); * if <code>false</code>, character boundaries are used * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored * @return the lines after wrapping */ public static String[] wrapStringToArray (String original, int width, boolean wrapWords, boolean removeNewLines) { // substitute original newlines with spaces, // remove newlines from head and tail if (removeNewLines) { while (original.startsWith ("\n")) // NOI18N original = original.substring (1); while (original.endsWith ("\n")) // NOI18N original = original.substring (0, original.length () - 1); original = original.replace ('\n', ' '); } if (width < 1) width = 1; if (original.length () <= width) { String s[] = new String [1]; s [0] = original; return s; } java.util.Vector lines = new java.util.Vector (); int lineStart = 0; // the position of start of currently processed line in the original string int lastSpacePos = -1; for (int i = 0; i < original.length (); i++) { if (lineStart >= original.length () - 1) break; // newline in the original string if (original.charAt (i) == '\n') { lines.addElement (original.substring (lineStart, i)); lineStart = i+1; lastSpacePos = -1; continue; } // remember last space position if (Character.isSpaceChar (original.charAt (i))) lastSpacePos = i; // last position in the original string if (i == original.length () - 1) { lines.addElement (original.substring (lineStart)); break; } // reached width if (i - lineStart == width) { if (wrapWords && (lastSpacePos != -1)) { lines.addElement (original.substring (lineStart, lastSpacePos)); lineStart = lastSpacePos + 1; // the space is consumed for the newline lastSpacePos = -1; } else { lines.addElement (original.substring (lineStart, i)); lineStart = i; lastSpacePos = -1; } } } String s[] = new String [lines.size ()]; lines.copyInto (s); return s; } /** Wrap multi-line strings. * @param original the original string to wrap * @param width the maximum width of lines * @param wrapWords if <code>true</code>, the lines are wrapped on word boundaries (if possible); * if <code>false</code>, character boundaries are used * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored * @return the whole string with embedded newlines */ public static String wrapString (String original, int width, boolean wrapWords, boolean removeNewLines) { // substitute original newlines with spaces, // remove newlines from head and tail if (removeNewLines) { while (original.startsWith ("\n")) // NOI18N original = original.substring (1); while (original.endsWith ("\n")) // NOI18N original = original.substring (0, original.length () - 1); original = original.replace ('\n', ' '); } if (width < 1) width = 1; if (original.length () <= width) return original; java.util.Vector lines = new java.util.Vector (); int lineStart = 0; // the position of start of currently processed line in the original string int lastSpacePos = -1; for (int i = 0; i < original.length (); i++) { if (lineStart >= original.length () - 1) break; // newline in the original string if (original.charAt (i) == '\n') { lines.addElement (original.substring (lineStart, i)); lineStart = i+1; lastSpacePos = -1; continue; } // remember last space position if (Character.isSpaceChar (original.charAt (i))) lastSpacePos = i; // last position in the original string if (i == original.length () - 1) { lines.addElement (original.substring (lineStart)); break; } // reached width if (i - lineStart == width) { if (wrapWords && (lastSpacePos != -1)) { lines.addElement (original.substring (lineStart, lastSpacePos)); lineStart = lastSpacePos + 1; // the space is consumed for the newline lastSpacePos = -1; } else { lines.addElement (original.substring (lineStart, i)); lineStart = i; lastSpacePos = -1; } } } StringBuffer retBuf = new StringBuffer (); for (java.util.Enumeration e = lines.elements (); e.hasMoreElements ();) { retBuf.append ((String) e.nextElement ()); retBuf.append ('\n'); } return retBuf.toString (); } /** Search-and-replace fixed string matches within a string. * @param original the original string * @param replaceFrom the substring to be find * @param replaceTo the substring to replace it with * @return a new string with all occurrences replaced */ public static String replaceString (String original, String replaceFrom, String replaceTo) { int index = 0; if ("".equals (replaceFrom)) return original; // NOI18N StringBuffer buf = new StringBuffer (); while (true) { int pos = original.indexOf (replaceFrom, index); if (pos == -1) { buf.append (original.substring (index)); return buf.toString (); } buf.append (original.substring (index, pos)); buf.append (replaceTo); index = pos + replaceFrom.length (); if (index == original.length ()) return buf.toString (); } } /** Turn full name of an inner class into its pure form. * @param fullName e.g. <code>some.pkg.SomeClass$Inner</code> * @return e.g. <code>Inner</code> */ public static final String pureClassName (final String fullName) { final int index = fullName.indexOf('$'); if ((index >= 0) && (index < fullName.length())) return fullName.substring(index+1, fullName.length()); return fullName; } /** Test whether the operating system supports icons on frames (windows). * @return <code>true</code> if it does <em>not</em> * */ public static final boolean isLargeFrameIcons() { return (getOperatingSystem () == OS_SOLARIS) || (getOperatingSystem () == OS_HP); } /** Compute hash code of array. * Asks all elements for their own code and composes the * values. * @param arr array of objects, can contain <code>null</code>s * @return the hash code * @see Object#hashCode */ public static int arrayHashCode (Object[] arr) { int c = 0; int len = arr.length; for (int i = 0; i < len; i++) { Object o = arr[i]; int v = o == null ? 1 : o.hashCode (); c += (v ^ i); } return c; } /** Safe equality check. * The supplied objects are equal if: <UL> * <LI> both are <code>null</code> * <LI> both are arrays with same length and equal items (if the items are arrays, * they are <em>not</em> checked the same way again) * <LI> the two objects are {@link Object#equal} * </UL> * This method is <code>null</code>-safe, so if one of the parameters is true and the second not, * it returns <code>false</code>. * @param o1 the first object to compare * @param o2 the second object to compare * @return <code>true</code> if the objects are equal */ public static boolean compareObjects (Object o1, Object o2) { return compareObjectsImpl (o1, o2, 1); } /** Safe equality check with array recursion. * @param o1 the first object to compare * @param o2 the second object to compare * @param checkArraysDepth the depth to which arrays should be compared for equality (negative for infinite depth, zero for no comparison of elements, one for shallow, etc.) * @return <code>true</code> if the objects are equal * @see #compareObjects(Object, Object) */ public static boolean compareObjectsImpl (Object o1, Object o2, int checkArraysDepth) { // handle null values if (o1 == null) return (o2 == null); else if (o2 == null) return false; // handle arrays if (checkArraysDepth > 0) { if ((o1 instanceof Object[]) && (o2 instanceof Object[])) { // Note: also handles multidimensional arrays of primitive types correctly. // I.e. new int[0][] instanceof Object[] Object[] o1a = (Object[]) o1; Object[] o2a = (Object[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) { if (! compareObjectsImpl (o1a[i], o2a[i], checkArraysDepth - 1)) { return false; } } return true; } else if ((o1 instanceof byte[]) && (o2 instanceof byte[])) { byte[] o1a = (byte[]) o1; byte[] o2a = (byte[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof short[]) && (o2 instanceof short[])) { short[] o1a = (short[]) o1; short[] o2a = (short[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof int[]) && (o2 instanceof int[])) { int[] o1a = (int[]) o1; int[] o2a = (int[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof long[]) && (o2 instanceof long[])) { long[] o1a = (long[]) o1; long[] o2a = (long[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof float[]) && (o2 instanceof float[])) { float[] o1a = (float[]) o1; float[] o2a = (float[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof double[]) && (o2 instanceof double[])) { double[] o1a = (double[]) o1; double[] o2a = (double[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof char[]) && (o2 instanceof char[])) { char[] o1a = (char[]) o1; char[] o2a = (char[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } else if ((o1 instanceof boolean[]) && (o2 instanceof boolean[])) { boolean[] o1a = (boolean[]) o1; boolean[] o2a = (boolean[]) o2; int l1 = o1a.length; int l2 = o2a.length; if (l1 != l2) return false; for (int i = 0; i < l1; i++) if (o1a[i] != o2a[i]) return false; return true; } // else not array type } // handle common objects--non-arrays, or arrays when depth == 0 return o1.equals (o2); } /** Assemble a human-presentable class name for a specified class. * Arrays are represented as e.g. <code>java.lang.String[]</code>. * @param clazz the class to name * @return the human-presentable name */ public static String getClassName (Class clazz) { // if it is an array, get short name of element type and append [] if (clazz.isArray ()) return getClassName (clazz.getComponentType ()) + "[]"; // NOI18N else return clazz.getName (); } /** Assemble a human-presentable class name for a specified class (omitting the package). * Arrays are represented as e.g. <code>String[]</code>. * @param clazz the class to name * @return the human-presentable name */ public static String getShortClassName (Class clazz) { // if it is an array, get short name of element type and append [] if (clazz.isArray ()) return getShortClassName (clazz.getComponentType ()) + "[]"; // NOI18N String name = clazz.getName ().replace ('$', '.'); return name.substring (name.lastIndexOf (".") + 1, name.length ()); // NOI18N } /** * Convert an array of objects to an array of primitive types. * E.g. an <code>Integer[]</code> would be changed to an <code>int[]</code>. * @param array the wrapper array * @return a primitive array * @throws IllegalArgumentException if the array element type is not a primitive wrapper */ public static Object toPrimitiveArray (Object[] array) { if (array instanceof Integer[]) { int[] r = new int [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Integer)array[i]) == null) ? 0 : ((Integer)array[i]).intValue (); return r; } if (array instanceof Boolean[]) { boolean[] r = new boolean [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Boolean)array[i]) == null) ? false : ((Boolean)array[i]).booleanValue (); return r; } if (array instanceof Byte[]) { byte[] r = new byte [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Byte)array[i]) == null) ? 0 : ((Byte)array[i]).byteValue (); return r; } if (array instanceof Character[]) { char[] r = new char [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Character)array[i]) == null) ? 0 : ((Character)array[i]).charValue (); return r; } if (array instanceof Double[]) { double[] r = new double [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Double)array[i]) == null) ? 0 : ((Double)array[i]).doubleValue (); return r; } if (array instanceof Float[]) { float[] r = new float [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Float)array[i]) == null) ? 0 : ((Float)array[i]).floatValue (); return r; } if (array instanceof Long[]) { long[] r = new long [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Long)array[i]) == null) ? 0 : ((Long)array[i]).longValue (); return r; } if (array instanceof Short[]) { short[] r = new short [array.length]; int i, k = array.length; for (i = 0; i < k; i++) r [i] = (((Short)array[i]) == null) ? 0 : ((Short)array[i]).shortValue (); return r; } throw new IllegalArgumentException (); } /** * Convert an array of primitive types to an array of objects. * E.g. an <code>int[]</code> would be turned into an <code>Integer[]</code>. * @param array the primitive array * @return a wrapper array * @throws IllegalArgumentException if the array element type is not primitive */ public static Object[] toObjectArray (Object array) { if (array instanceof Object[]) return (Object[]) array; if (array instanceof int[]) { int i, k = ((int[])array).length; Integer[] r = new Integer [k]; for (i = 0; i < k; i++) r [i] = new Integer (((int[]) array)[i]); return r; } if (array instanceof boolean[]) { int i, k = ((boolean[])array).length; Boolean[] r = new Boolean [k]; for (i = 0; i < k; i++) r [i] = new Boolean (((boolean[]) array)[i]); return r; } if (array instanceof byte[]) { int i, k = ((byte[])array).length; Byte[] r = new Byte [k]; for (i = 0; i < k; i++) r [i] = new Byte (((byte[]) array)[i]); return r; } if (array instanceof char[]) { int i, k = ((char[])array).length; Character[] r = new Character [k]; for (i = 0; i < k; i++) r [i] = new Character (((char[]) array)[i]); return r; } if (array instanceof double[]) { int i, k = ((double[])array).length; Double[] r = new Double [k]; for (i = 0; i < k; i++) r [i] = new Double (((double[]) array)[i]); return r; } if (array instanceof float[]) { int i, k = ((float[])array).length; Float[] r = new Float [k]; for (i = 0; i < k; i++) r [i] = new Float (((float[]) array)[i]); return r; } if (array instanceof long[]) { int i, k = ((long[])array).length; Long[] r = new Long [k]; for (i = 0; i < k; i++) r [i] = new Long (((long[]) array)[i]); return r; } if (array instanceof short[]) { int i, k = ((short[])array).length; Short[] r = new Short [k]; for (i = 0; i < k; i++) r [i] = new Short (((short[]) array)[i]); return r; } throw new IllegalArgumentException (); } /** * Get the object type for given primitive type. * * @param c primitive type (e.g. <code>int</code>) * @return object type (e.g. <code>Integer</code>) */ public static Class getObjectType (Class c) { if (!c.isPrimitive ()) return c; if (c == Integer.TYPE) return Integer.class; if (c == Boolean.TYPE) return Boolean.class; if (c == Byte.TYPE) return Byte.class; if (c == Character.TYPE) return Character.class; if (c == Double.TYPE) return Double.class; if (c == Float.TYPE) return Float.class; if (c == Long.TYPE) return Long.class; if (c == Short.TYPE) return Short.class; throw new IllegalArgumentException (); } /** * Get the primitive type for given object type. * * @param c object type (e.g. <code>Integer</code>) * @return primitive type (e.g. <code>int</code>) */ public static Class getPrimitiveType (Class c) { if (!c.isPrimitive ()) return c; if (c == Integer.class) return Integer.TYPE; if (c == Boolean.class) return Boolean.TYPE; if (c == Byte.class) return Byte.TYPE; if (c == Character.class) return Character.TYPE; if (c == Double.class) return Double.TYPE; if (c == Float.class) return Float.TYPE; if (c == Long.class) return Long.TYPE; if (c == Short.class) return Short.TYPE; throw new IllegalArgumentException (); } /** Find a focus-traverable component. * @param c the component to look in * @return the same component if traversable, else a child component if present, else <code>null</code> * @see Component#isFocusTraversable */ public static Component getFocusTraversableComponent (Component c) { if (c.isFocusTraversable ()) return c; if (!(c instanceof Container)) return null; int i, k = ((Container)c).getComponentCount (); for (i = 0; i < k; i++) { Component v = ((Container)c).getComponent (i); if (v != null) return v; } return null; } /** Parses parameters from a given string in shell-like manner. * Users of the Bourne shell (e.g. on Unix) will already be familiar with the behavior. * Otherwise, see {@link org.openide.execution.NbProcessDescriptor#getProcessArgs} * for examples of what it does. * @param s a string to parse * @return an array of parameters */ public static String[] parseParameters(String s) { int NULL = 0x0; // STICK + whitespace or NULL + non_" int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ // NOI18N int INPARAMPENDING = 0x2; // INPARAM + \ int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N int STICKPENDING = 0x8; // STICK + \ Vector params = new Vector(5,5); char c; int state = NULL; StringBuffer buff = new StringBuffer(20); int slength = s.length(); for (int i = 0; i < slength; i++) { c = s.charAt(i); if (Character.isWhitespace(c)) { if (state == NULL) { if (buff.length () > 0) { params.addElement(buff.toString()); buff.setLength(0); } } else if (state == STICK) { params.addElement(buff.toString()); buff.setLength(0); state = NULL; } else if (state == STICKPENDING) { buff.append('\\'); params.addElement(buff.toString()); buff.setLength(0); state = NULL; } else if (state == INPARAMPENDING) { state = INPARAM; buff.append('\\'); buff.append(c); } else { // INPARAM buff.append(c); } continue; } if (c == '\\') { if (state == NULL) { ++i; if (i < slength) { char cc = s.charAt(i); if (cc == '"' || cc == '\\') { buff.append(cc); } else if (Character.isWhitespace(cc)) { buff.append(c); --i; } else { buff.append(c); buff.append(cc); } } else { buff.append('\\'); break; } continue; } else if (state == INPARAM) { state = INPARAMPENDING; } else if (state == INPARAMPENDING) { buff.append('\\'); state = INPARAM; } else if (state == STICK) { state = STICKPENDING; } else if (state == STICKPENDING) { buff.append('\\'); state = STICK; } continue; } if (c == '"') { if (state == NULL) { state = INPARAM; } else if (state == INPARAM) { state = STICK; } else if (state == STICK) { state = INPARAM; } else if (state == STICKPENDING) { buff.append('"'); state = STICK; } else { // INPARAMPENDING buff.append('"'); state = INPARAM; } continue; } if (state == INPARAMPENDING) { buff.append('\\'); state = INPARAM; } else if (state == STICKPENDING) { buff.append('\\'); state = STICK; } buff.append(c); } // collect if (state == INPARAM) { params.addElement(buff.toString()); } else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) { buff.append('\\'); params.addElement(buff.toString()); } else { // NULL or STICK if (buff.length() != 0) { params.addElement(buff.toString()); } } String[] ret = new String[params.size()]; params.copyInto(ret); return ret; } // // Key conversions // /** Initialization of the names and values */ private static void initialize () { names = new HashMap (); values = new HashMap (); Field[] fields = KeyEvent.class.getDeclaredFields (); for (int i = 0; i < fields.length; i++) { if (Modifier.isStatic (fields[i].getModifiers ())) { String name = fields[i].getName (); if (name.startsWith ("VK_")) { // NOI18N // exclude VK name = name.substring (3); try { int numb = fields[i].getInt (null); Integer value = new Integer (numb); names.put (name, value); values.put (value, name); } catch (IllegalArgumentException ex) { } catch (IllegalAccessException ex) { } } } } } /** Converts a Swing key stroke descriptor to a familiar Emacs-like name. * @param stroke key description * @return name of the key (e.g. <code>CS-F1</code> for control-shift-function key one) * @see #stringToKey */ public static String keyToString (KeyStroke stroke) { StringBuffer sb = new StringBuffer (); // add modifiers that must be pressed if (addModifiers (sb, stroke.getModifiers ())) { sb.append ('-'); } String c = (String)values.get (new Integer (stroke.getKeyCode ())); if (c == null) { sb.append (stroke.getKeyChar ()); } else { sb.append (c); } return sb.toString (); } /** Construct a new key description from a given universal string * description. * Provides mapping between Emacs-like textual key descriptions and the * <code>KeyStroke</code> object used in Swing. * <P> * This format has following form: * <P><code>[C][A][S][M]-<em>identifier</em></code> * <p>Where: * <UL> * <LI> <code>C</code> stands for the Control key * <LI> <code>A</code> stands for the Alt key * <LI> <code>S</code> stands for the Shift key * <LI> <code>M</code> stands for the Meta key * </UL> * Every modifier before the hyphen must be pressed. * <em>identifier</EM> can be any text constant from {@link KeyEvent} but * without the leading <code>VK_</code> characters. So {@link KeyEvent#VK_ENTER} is described as * <code>ENTER</code>. * * @param s the string with the description of the key * @return key description object, or <code>null</code> if the string does not represent any valid key */ public static KeyStroke stringToKey (String s) { StringTokenizer st = new StringTokenizer (s.toUpperCase (), "-", true); // NOI18N int needed = 0; int lastModif = -1; try { for (;;) { String el = st.nextToken (); // required key if (el.equals ("-")) { // NOI18N if (lastModif != -1) { needed |= lastModif; lastModif = -1; } continue; } // if there is more elements if (st.hasMoreElements ()) { // the text should describe modifiers lastModif = readModifiers (el); } else { // last text must be the key code Integer i = (Integer)names.get (el); if (i != null) { return KeyStroke.getKeyStroke (i.intValue (), needed); } else { return null; } } } } catch (NoSuchElementException ex) { return null; } } /** Convert a space-separated list of user-friendly key binding names to a list of Swing key strokes. * @param s the string with keys * @return array of key strokes, or <code>null</code> if the string description is not valid * @see #stringToKey */ public static KeyStroke[] stringToKeys (String s) { StringTokenizer st = new StringTokenizer (s.toUpperCase (), " "); // NOI18N ArrayList arr = new ArrayList (); while (st.hasMoreElements ()) { s = st.nextToken (); KeyStroke k = stringToKey (s); if (k == null) return null; arr.add (k); } return (KeyStroke[])arr.toArray (new KeyStroke[arr.size ()]); } /** Adds characters for modifiers to the buffer. * @param buf buffer to add to * @param modif modifiers to add (KeyEvent.XXX_MASK) * @return true if something has been added */ private static boolean addModifiers (StringBuffer buf, int modif) { boolean b = false; if ((modif & KeyEvent.CTRL_MASK) != 0) { buf.append("C"); // NOI18N b = true; } if ((modif & KeyEvent.ALT_MASK) != 0) { buf.append("A"); // NOI18N b = true; } if ((modif & KeyEvent.SHIFT_MASK) != 0) { buf.append("S"); // NOI18N b = true; } if ((modif & KeyEvent.META_MASK) != 0) { buf.append("M"); // NOI18N b = true; } return b; } /** Reads for modifiers and creates integer with required mask. * @param s string with modifiers * @return integer with mask * @exception NoSuchElementException if some letter is not modifier */ private static int readModifiers (String s) throws NoSuchElementException { int m = 0; for (int i = 0; i < s.length (); i++) { switch (s.charAt (i)) { case 'C': m |= KeyEvent.CTRL_MASK; break; case 'A': m |= KeyEvent.ALT_MASK; break; case 'M': m |= KeyEvent.META_MASK; break; case 'S': m |= KeyEvent.SHIFT_MASK; break; default: throw new NoSuchElementException (); } } return m; } /** Exception indicating that a given list could not be partially-ordered. * @see #partialSort */ public static class UnorderableException extends RuntimeException { private Collection unorderable; private Map deps; static final long serialVersionUID =6749951134051806661L; /** Create a new unorderable-list exception with no detail message. * @param unorderable a collection of list elements which could not be ordered * (because there was some sort of cycle) * @param deps dependencies associated with the list; a map from list elements * to sets of list elements which that element must appear after */ public UnorderableException (Collection unorderable, Map deps) { super (/* "Cannot be ordered: " + unorderable */); // NOI18N this.unorderable = unorderable; this.deps = deps; } /** Create a new unorderable-list exception with a specified detail message. * @param message the detail message * @param unorderable a collection of list elements which could not be ordered * (because there was some sort of cycle) * @param deps dependencies associated with the list; a map from list elements * to sets of list elements which that element must appear after */ public UnorderableException (String message, Collection unorderable, Map deps) { super (message); this.unorderable = unorderable; this.deps = deps; } /** Get the unorderable elements. * @return the elements * @see #UnorderableException(Collection,Map) */ public Collection getUnorderable () { return unorderable; } /** Get the dependencies. * @return the dependencies * @see #UnorderableException(Collection,Map) */ public Map getDeps () { return deps; } } /** Sort a list according to a specified partial order. * Note that in the current implementation, the comparator will be called * exactly once for each distinct pair of list elements, ignoring order, * so caching its results is a waste of time. * @param l the list to sort (will not be modified) * @param c a comparator to impose the partial order; "equal" means that the elements * are not ordered with respect to one another, i.e. may be only a partial order * @param stable whether to attempt a stable sort, meaning that the position of elements * will be disturbed as little as possible; might be slightly slower * @return the partially-sorted list * @throws UnorderableException if the specified partial order is inconsistent on this list */ public static List partialSort (List l, Comparator c, boolean stable) throws UnorderableException { // map from objects in the list to null or sets of objects they are greater than // (i.e. must appear after): Map deps = new HashMap (); // Map<Object,Set<Object>> int size = l.size (); // Create a table of dependencies. for (int i = 0; i < size; i++) { for (int j = i + 1; j < size; j++) { int cmp = c.compare (l.get (i), l.get (j)); if (cmp != 0) { Object earlier = l.get (cmp < 0 ? i : j); Object later = l.get (cmp > 0 ? i : j); Set s = (Set) deps.get (later); if (s == null) deps.put (later, s = new HashSet ()); s.add (earlier); } } } // Lists of items to process, and items sorted. List left = new LinkedList (l); List sorted = new ArrayList (size); while (left.size () > 0) { boolean stillGoing = false; Iterator it = left.iterator (); while (it.hasNext ()) { Object elt = it.next (); Set eltDeps = (Set) deps.get (elt); if (eltDeps == null || eltDeps.size () == 0) { // This one is OK to add to the result now. it.remove (); stillGoing = true; sorted.add (elt); // Mark other elements that should be later // than this as having their dep satisfied. Iterator it2 = left.iterator (); while (it2.hasNext ()) { Object elt2 = it2.next (); Set eltDeps2 = (Set) deps.get (elt2); if (eltDeps2 != null) eltDeps2.remove (elt); } if (stable) break; } } if (! stillGoing) throw new UnorderableException (left, deps); } return sorted; } /** cache for old_name:new_name mapping */ private static Reference nameMap; /** Handles repackaging whole IDE for runtime compatibility. * It should not be used by new code except during a package rename. * * @param name fully qualified name of a class to translate * @exception NullPointerException iff <tt>className</tt> is <tt>null</tt> */ public static String translate(final String className) { if (className.length() == 0) { return className; } String name; int arrayPrefix; if (className.charAt(0) == '[') { for (arrayPrefix = 1; className.charAt(arrayPrefix) == '['; arrayPrefix++); if (className.charAt(arrayPrefix++) != 'L') { return className; } name = className.substring(arrayPrefix); } else { name = className; arrayPrefix = -1; } // Obviously this shortcut depends on the contents on the packages.txt: if (name.startsWith ("com" + ".netbeans.") || name.startsWith ("com" + ".sun.forte4j.")) { String packageName; int dot = name.lastIndexOf('.'); if ((dot > 0) && (dot != name.length() - 1)) { // last char packageName = name.substring(0, dot); } else { return className; } try { // line_no * 2 String[][] map; // acquire mapping if (nameMap == null || (map = (String[][]) nameMap.get()) == null) { map = loadNameMapping(); nameMap = new SoftReference(map); } // search for "the" name final int mapsize = map.length; for (int i = 0; i < mapsize; i++) { if (packageName.startsWith(map[i][0])) { if (arrayPrefix < 0) { return map[i][1] + name.substring(map[i][0].length()); } else { return className.substring(0, arrayPrefix) + map[i][1] + name.substring(map[i][0].length()); } } } } catch (IOException e) { TopManager.getDefault().notifyException(e); } } // default return className; } /** Loads name mapping from file org/openide/util/packages.txt */ private static String[][] loadNameMapping() throws IOException { BufferedReader reader = new BufferedReader( new InputStreamReader( Utilities.class.getClassLoader().getResourceAsStream("org/openide/util/packages.txt") ) ); ArrayList chunks = new ArrayList(50); for (;;) { String line = reader.readLine(); String[] pair = parseLine(line); if (pair == null) { // EOF break; } chunks.add(pair); } Collections.sort(chunks, new StringArrayComparator()); final int pairslen = chunks.size(); String[][] mapping = new String[pairslen][2]; for (int i = 0; i < pairslen; i++) { String[] chunk = (String[]) chunks.get(i); mapping[i][0] = chunk[0]; mapping[i][1] = chunk[1]; } return mapping; } private static String[] parseLine(final String line) { if (line == null) { return null; } final int slen = line.length(); int space = line.indexOf(' '); if (space <= 0 || (space == slen - 1)) { return null; } String[] chunk = new String[] {line.substring(0, space), null}; space++; int c; while ((space < slen) && (line.charAt(space++) == ' ')); if (space == slen) { return null; } String token = line.substring(--space); token = token.trim(); chunk[1] = token; return chunk; } /** Compares to object by length of String returned by toString(). */ static final class StringArrayComparator implements Comparator { public boolean equals(Object o) { return super.equals(o); } public int compare(Object o1, Object o2) { String[] s1 = (String[]) o1; String[] s2 = (String[]) o2; return (s2[0].length() - s1[0].length()); } } } /* * Log * 31 Gandalf 1.30 4/15/00 Jesse Glick Fixed translate (it did * not produce the correct result). * 30 Gandalf 1.29 4/15/00 Jesse Glick Even more minor * massages. * 29 Gandalf 1.28 4/14/00 Jesse Glick Minor massages to * translate function. * 28 Gandalf 1.27 4/14/00 Ales Novak translate() added * 27 Gandalf 1.26 2/14/00 Ian Formanek Added constant for * Windows 2000, Win2000 correctly recognized as "isWindows" * 26 Gandalf 1.25 1/15/00 Pavel Buzek #5326 * 25 Gandalf 1.24 1/13/00 Ian Formanek NOI18N * 24 Gandalf 1.23 1/12/00 Pavel Buzek I18N * 23 Gandalf 1.22 1/7/00 Pavel Buzek create new property * descriptor for cursor property of java.awt.Component subclasses * 22 Gandalf 1.21 11/26/99 Patrik Knakal * 21 Gandalf 1.20 11/25/99 Jesse Glick Added partialSort * function. * 20 Gandalf 1.19 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 19 Gandalf 1.18 9/7/99 Ian Formanek "default" is correctly * treated as not being Java identifier * 18 Gandalf 1.17 7/13/99 Jesse Glick Fixed to handle arrays * of primitives. * 17 Gandalf 1.16 6/10/99 Jaroslav Tulach Recognizes SunOSxxxxx as * OS_SOLARIS * 16 Gandalf 1.15 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 15 Gandalf 1.14 6/4/99 Ales Novak fix for parsing of * commandline * 14 Gandalf 1.13 5/15/99 Jesse Glick [JavaDoc], and * constructor private for stylistic reasons. * 13 Gandalf 1.12 4/1/99 Jan Jancura bug in getShortClassName * 12 Gandalf 1.11 3/26/99 David Simonek pureName removed (was * useless) * 11 Gandalf 1.10 3/21/99 Jaroslav Tulach Keys. * 10 Gandalf 1.9 3/14/99 Jaroslav Tulach Change of * MultiDataObject.Entry. * 9 Gandalf 1.8 3/12/99 Jaroslav Tulach * 8 Gandalf 1.7 3/8/99 Ian Formanek Removed * getMultiLineString * 7 Gandalf 1.6 3/4/99 Petr Hamernik * 6 Gandalf 1.5 3/4/99 Jaroslav Tulach API cleaning * 5 Gandalf 1.4 3/4/99 Petr Hamernik * 4 Gandalf 1.3 2/10/99 David Simonek * 3 Gandalf 1.2 2/3/99 David Simonek * 2 Gandalf 1.1 1/20/99 David Simonek rework of class DO * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ */